#include "sbrbtree.h"
#include "sbalance.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

struct rb_root sb_timer_tree = RB_ROOT;

struct sb_event * sb_timer_search(struct rb_root *root, unsigned long timeout_time)
{
        struct rb_node *node = root->rb_node;
	struct sb_event *event = NULL;

        while (node) {
                event = container_of(node, struct sb_event, node);

                if (timeout_time < event->timeout_time)
                        node = node->rb_left;
                else if (timeout_time > event->timeout_time)
                        node = node->rb_right;
                else
                        return event;
        }

        return NULL;
}

int sb_timer_insert(struct rb_root *root, struct sb_event *event)
{
        struct rb_node **new = &(root->rb_node), *parent = NULL;

        /* Figure out where to put new node */
        while (*new) {
                struct sb_event *this = container_of(*new, struct sb_event, node);

                parent = *new;
                if (event->timeout_time < this->timeout_time)
                        new = &((*new)->rb_left);
                else if (event->timeout_time > this->timeout_time)
                        new = &((*new)->rb_right);
                else {
                        new = &((*new)->rb_left);
                        break;
                }
        }

        /* Add new node and rebalance tree. */
        rb_link_node(&event->node, parent, new);
        rb_insert_color(&event->node, root);

        return 0;
}

void sb_timer_push_event(struct sb_event *event)
{
	if (event->in_timer_set)	return;

	sb_timer_insert(&sb_timer_tree, event);
	event->in_timer_set = 1;
}

void sb_timer_pop_event(struct sb_event *ev)
{
	if (!ev->in_timer_set)	return;

	rb_erase(&ev->node, &sb_timer_tree);
	ev->in_timer_set = 0;
}

unsigned long sb_find_lastest_timer()
{
	struct rb_node *node = NULL;
	struct sb_event *timer = NULL;
	
	node = rb_first(&sb_timer_tree); 
	if (node == NULL)
		return 1000;	/* no timer */

	timer = rb_entry(node, struct sb_event, node);
	if (timer->timeout_time < sb_current_msec_time()) {
		return 	sb_current_msec_time() - timer->timeout_time;
	}
	else 
		return 0;
}

void sb_process_expire_timer(struct sb_cycle_env *env)
{
	struct rb_node *node = NULL;
	struct sb_event *event = NULL;
	
	unsigned long current_time =  sb_current_msec_time();

	for (;;) {
		node = rb_first(&sb_timer_tree); 
		if (node == NULL) break;

		event = container_of(node, struct sb_event, node);
		if (event->timeout_time <= current_time) {
			/* timeout process */
			event->timeout = 1;
			if (event->handler) {
				(void)event->handler(env, event);
			}
			
			/* possible handler delete the node */
			if (event->in_timer_set) {
				rb_erase(node, &sb_timer_tree);
			}
			event->in_timer_set = 0;
		}
		else {
			break;
		}
	}
}
